/*
 * Created by Jesse Phillips
 * Created on March 5, 2006
 */

/**
 * Authors: Jesse Phillips, jesse.phillips@eagles.ewu.edu
 *				Ben Poplawski
 * Date: Nov 8, 2006
 * License: GPL v2
 */

/**
 * An attempt to create a fuzzy logic AI based on the tags files have. It has
 * ended up being more of an algorithm then an AI.
 *
 * This test will use fake files read in from a file.
 */
import tag;

import std.string;
import std.file;
import std.stdio;

int main()
{
	char[] input2 = cast(char[])read("files.in");
	char[][] input = splitlines(input2);
	// The list will hold the groups of tags
	// A group will be the tags of a file.
	TagGroup[] list = new TagGroup[50];
	// The "Tag" will contain Tags that would be sub Tags
	TagGroup[Tag] category; 
	Tag[] tags = new Tag[100];

	/**
	 * Record all of the tags available into an array.
	 */
	int i = 0;
	int j = 0;
	foreach(char[] c; input)
	{
		// Tags are delimited by "; " for the tesing of this algorithm.
		char[][] single = split(c, "; "); 

		// Build a list of all the tags, and count repeats.
		// ct = character tag
		// t = is a Tag
		foreach(char[] ct; single)
		{
			bool has = false;
			foreach(t;tags)
			{
				if(t is null) break;
				if(t.name == ct)
				{
					has = true;
					t.count++;
				}
			}
			if(!has)
				if(ct != "" && ct != " ")
				{
					tags[i] = new Tag(ct);
					category[tags[i++]] = new TagGroup(0);
				}
		}

		/// Build an array of all the grouped tags.
		/// Each files tag set is a group.
		TagGroup group = new TagGroup();
		foreach(char[] ct; single)
			foreach(t; tags)
			{
				if(t is null) break;
				if(t.name == ct && ct != "" && ct != "\n")
				{
					group.addTag(t);
				}
			}
		if(!group.empty())
			list[j++] = group;
	}
	
	/**
	 * Run through all the tags to find out what tags
	 * occur most often with that tag. And group them.
	 *
	 * This loop is probably the least efficient way to
	 * accomplish the task. But it works and needs expanded.
	 * The task is to find out what tags should appear as
	 * sub tags to that tag. The current "AI" will tag
	 * the tags that occur half as often, as the selected tag,
	 * or more.
	 */
	int index = 0;
	foreach(Tag cat;tags)
	{
		if(cat !is null)
		{
			foreach(Tag find;tags)
			{
				if(find !is null)
				{
					int numOfTags = countTagWith(cat, find, list);
					// Tags that occur more than half the time of the
					// category should not be add as a sub Tag.
					if(find.count <= (cat.count/2+1))
					{
						if(numOfTags > 0)
						{
							category[cat].addTag(find);
							// If the number of tags found in the category is less
							// than the count of the category then that tag should be
							// deeper in the hierarchy.
						   if(numOfTags <= cat.count)
							{
								category[find].level = category[find].level + 1;
							}//end if (numOfTags <= cat.count)
						}//end if (numOfTags > 0)
					}//end if (find.count <= (cat.count / 2 + 1))
					
					/* A Tag may be required to reside deeper in one category than
					 * another category. This means that if foo resides in bar
					 * (/bar/foo) and foo also resides in label2
					 * (/label1/label2/foo) then foo would have a level of 3. (foo
					 * in bar foo.level += 1; foo in label2 foo.level += 2; thus
					 * foo.level == 3)
					 */

				}//end if (find !is null)
			}//end foreach (find; tags)
		}//end if (cat !is null)
	}//end foreach (cat; tags)

	// This is an attempt to print out what the hierarchy looks like.
	debug(3)
	{
		// category is a hashtable with a Tag as a reference
		Tag[] keys = category.keys;

		foreach(Tag key; keys)
			if(category[key].level == 0)
			{
				Tag lowest = null;
				writefln("/%s", key);
				foreach(Tag sub; category[key].getTags())
				{
					if(sub !is null)
						if(lowest !is null)
						{
							if(category[sub].level < category[lowest].level)
								lowest = sub;
						}//end if(lowes !is null)
						else
						  lowest = sub;
							
				}//end foreach
				if(lowest !is null)
					writefln("/%s/%s", key, lowest);
			}//end if
	}//end debug (3)

	return 0;
}

/**
	Looks for and counts the number of times 'find' ocurrs
	with 'cat.'
*/
int countTagWith(Tag cat, Tag find, TagGroup[] list)
{
	int count = 0;
	if(cat.name != find.name)
		foreach(TagGroup tg; list)
		{
			if(tg is null) continue;
			Tag result = tg.hasTag(cat);
			if(result !is null)
				if(tg.hasTag(find) !is null)
					count++;
		}
	return count;
}
